home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 November: Tool Chest / Dev.CD Nov 98 TC.toast / Sample Code / Snippets / Sound / SoundConvert / SoundConvert.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-03-14  |  21.1 KB  |  876 lines  |  [TEXT/CWIE]

  1. /*
  2. **    Apple Macintosh Developer Technical Support
  3. **
  4. **    Demonstration of sound format conversion support in Sound Manager 3.2
  5. **
  6. **    by Andrew Wulf, Apple Developer Technical Support
  7. **
  8. **    File:        SoundConvert.c
  9. **
  10. **    Copyright © 1996 Apple Computer, Inc.
  11. **    All rights reserved.
  12. **
  13. **    You may incorporate this sample code into your applications without
  14. **    restriction, though the sample code has been provided "AS IS" and the
  15. **    responsibility for its operation is 100% yours.  However, what you are
  16. **    not permitted to do is to redistribute the source as "DSC Sample Code"
  17. **    after having made changes. If you're going to re-distribute the source,
  18. **    we require that you make it clear in the source that the code was
  19. **    descended from Apple Sample Code, but that you've made changes.
  20. */
  21.  
  22. #include <Quickdraw.h>
  23. #include <Windows.h>
  24. #include <Dialogs.h>
  25. #include <Files.h>
  26. #include <StandardFile.h>
  27. #include <Packages.h>
  28. #include <OSEvents.h>
  29. #include <Memory.h>
  30. #include <OSUtils.h>
  31. #include <ToolUtils.h>
  32. #include <Types.h>
  33. #include <TextUtils.h>
  34. #include <SegLoad.h>
  35. #include <Gestalt.h>
  36. #include <AIFF.h>
  37. #include <stdio.h>
  38. #include <strings.h>
  39. #include <string.h>
  40. // the following are from sound manager 3.2, not yet in ETO 19
  41. #include <Sound.h>
  42. #include <SoundComponents.h>
  43. #include <SoundInput.h>
  44.  
  45. #define FormatPopupMenu 128
  46. #define RatePopupMenu 129
  47. #define DialogID 129
  48.  
  49. enum {
  50.     Button_Quit = 1,
  51.     Button_Input = 3,
  52.     Button_Convert,
  53.     Static_Filename,
  54.     Radio_8bit,
  55.     Radio_16bit,
  56.     Radio_Mono,
  57.     Radio_Stereo,
  58.     Popup_Format,
  59.     Popup_Rate,
  60.     Static_Notes = 13
  61.     };
  62.  
  63. typedef struct
  64.     {
  65.     FSSpec file;
  66.     SoundComponentData info;
  67.     unsigned long numFrames;
  68.     unsigned long dataOffset;
  69.     Ptr buffer;
  70.     } SoundFileInfo;
  71.  
  72. typedef struct
  73.     {
  74.     FSSpec file;
  75.     SoundComponentData info;
  76.     unsigned long inputBufferFrames;
  77.     unsigned long inputBufferBytes;
  78.     unsigned long outputBytes;
  79.     Ptr buffer;
  80.     } SoundConvertInfo;    
  81.  
  82. typedef struct
  83.     {
  84.     OSType formatType;
  85.     Boolean isCompressor;
  86.     Boolean isDecompressor;
  87.     short dummy;
  88.     } MenuToFormatType, *MenuToFormatTypePtr, **MenuToFormatTypeHandle;
  89.  
  90. MenuToFormatTypeHandle MenuToFormatTypeList = 0;    // used to map menu to format type
  91. short Group1;
  92. short Group2;
  93. Point Where;
  94. short Modifiers;
  95. SoundFileInfo FileInfo = { 0, 0, "\p" };
  96. long BuffersSize= 0;
  97.  
  98. #define LAST_SAMPLE_MENU 5
  99. Fixed MenuToSampleRates[LAST_SAMPLE_MENU]
  100.     = { rate44khz, rate22050hz, rate22khz, rate11khz, rate11025hz };
  101.  
  102. #if ((!defined(__MWERKS__))&&(!defined(THINK_C)))
  103.     QDGlobals qd;
  104. #endif
  105.  
  106. OSErr ShowErr(char*text, short err);
  107. void ShowErrAndQuit(char*text, short err);
  108. void BuildFormatMenu(void);
  109. void SetRadio(DialogPtr dlog, short item, short val);
  110. short GetRadio(DialogPtr dlog, short item);
  111. pascal Boolean MyFilter( DialogPtr, EventRecord *, short *);
  112. DialogPtr OpenDialog(void);
  113. void RunDialog(DialogPtr dialog);
  114. void DoDialogUpdate( DialogPtr dialog);
  115. void ShowAControl( DialogPtr dlog, short item );
  116. Boolean GetInputFile(void);
  117. void DoConversion( DialogPtr dialog );
  118. void ShowInfo( DialogPtr dialog );
  119. void SetStaticText( DialogPtr dlog, short item, Byte* s );
  120. void MakeInfoString( SoundFileInfo*info, Byte* s );
  121. void GetWantedData(DialogPtr dialog, SoundComponentData* info);
  122. short GetAControlValue(DialogPtr dlog, short item);
  123. OSErr ConvertSound( SoundFileInfo*, SoundConvertInfo*, SoundConverter sc );
  124. void HiliteAControl( DialogPtr dlog, short item, Boolean state );
  125. OSErr ConvertBufferInMemory( SoundFileInfo*input, short inputFile,
  126.                     SoundConvertInfo*output, short outputFile, SoundConverter sc );
  127. OSErr ConvertBufferInChunks( SoundFileInfo*input, short inputFile,
  128.                     SoundConvertInfo*output, short outputFile, SoundConverter sc );
  129.  
  130. // ----------------------------------------------------------------------------------
  131.  
  132. void main()
  133.     {
  134.     NumVersion version;
  135.     DialogPtr dialog;
  136.  
  137.     MaxApplZone();
  138.  
  139.     InitGraf(&qd.thePort);
  140.     FlushEvents(everyEvent, 0);
  141.     InitWindows();
  142.     InitDialogs(0);
  143.     InitCursor();
  144.     
  145.     version = SndSoundManagerVersion();
  146.     if ( ! ( version.majorRev >= 3 && version.minorAndBugRev >= 0x20 ) )
  147.         ShowErrAndQuit( "Sound Manager is older than 3.2", 0 );
  148.     
  149.     dialog = OpenDialog();
  150.     if ( dialog )
  151.         RunDialog(dialog);
  152.     }
  153.  
  154. // Create our one and only dialog
  155.  
  156. DialogPtr OpenDialog()
  157.     {
  158.     DialogPtr dialog;
  159.  
  160.     InsertMenu(GetMenu(FormatPopupMenu),-1);
  161.     InsertMenu(GetMenu(RatePopupMenu),-1);
  162.     BuildFormatMenu();
  163.     
  164.     dialog = GetNewDialog( DialogID, 0, (WindowPtr)(-1L) );
  165.     SetPort(dialog);
  166.  
  167.     SetRadio( dialog, Group1 = Radio_8bit, 1);
  168.     SetRadio( dialog, Radio_16bit, 0);
  169.     SetRadio( dialog, Group2 = Radio_Mono, 1);
  170.     SetRadio( dialog, Radio_Stereo, 0);
  171.     
  172.     ShowAControl( dialog, Popup_Format );
  173.     ShowAControl( dialog, Popup_Rate );
  174.     
  175.     HiliteAControl( dialog, Button_Convert, false );
  176.  
  177.     ShowWindow(dialog);
  178.     
  179.     return dialog;
  180.     }
  181.  
  182. // Execute dialog until quit button hit
  183.  
  184. void RunDialog( DialogPtr dialog )
  185.     {
  186.     Boolean keepGoing = true;
  187.     short itemHit;
  188.     ModalFilterUPP filter = NewModalFilterProc( MyFilter );
  189.     
  190.     while (keepGoing)
  191.         {
  192.         ModalDialog( filter, &itemHit );
  193.         
  194.         switch( itemHit )
  195.             {
  196.             case Button_Quit:
  197.                 keepGoing = false;
  198.                 break;
  199.  
  200.             case Button_Input:
  201.                 if ( GetInputFile() )
  202.                     HiliteAControl( dialog, Button_Convert, true );
  203.                 ShowInfo( dialog );
  204.                 break;
  205.  
  206.             case Button_Convert:
  207.                 DoConversion( dialog );
  208.                 break;
  209.             
  210.             case Radio_8bit:
  211.             case Radio_16bit:            
  212.                 if ( itemHit != Group1 )
  213.                     {
  214.                     SetRadio( dialog, Group1, 0 );
  215.                     Group1 = ( Group1 == Radio_8bit ) ? Radio_16bit : Radio_8bit;
  216.                     SetRadio( dialog, Group1, 1 );
  217.                     }                
  218.                 break;
  219.  
  220.             case Radio_Mono:
  221.             case Radio_Stereo:
  222.                 if ( itemHit != Group2 )
  223.                     {
  224.                     SetRadio( dialog, Group2, 0 );
  225.                     Group2 = ( Group2 == Radio_Mono ) ? Radio_Stereo : Radio_Mono;
  226.                     SetRadio( dialog, Group2, 1 );
  227.                     }                
  228.                 break;
  229.             
  230.             case Popup_Format:
  231.             case Popup_Rate:
  232.                 break;
  233.             }
  234.         }
  235.     }
  236.  
  237. // Get a file to work on
  238.  
  239. Boolean GetInputFile()
  240.     {
  241.     StandardFileReply reply;
  242.     SFTypeList types = { 'AIFF', 'AIFC', 0, 0 };
  243.     
  244.     StandardGetFile( 0L, 2, types, &reply );
  245.     if ( reply.sfGood )
  246.         FileInfo.file = reply.sfFile;
  247.     
  248.     return FileInfo.file.name[0] != 0;
  249.     }
  250.  
  251. // Pick an output file and convert it
  252.  
  253. void DoConversion( DialogPtr dialog )
  254.     {
  255.     StandardFileReply reply;
  256.     Str63 s, t;
  257.  
  258.     BlockMove( FileInfo.file.name, s, FileInfo.file.name[0]+1 ); p2cstr(s);
  259.     sprintf( (char*)t, "%s.mod", (char*)s ); c2pstr((char*)t);
  260.     if ( t[0] > 31 )
  261.         t[0] = 31;
  262.     
  263.     StandardPutFile( "\pSave converted sound as:", t, &reply );
  264.     if ( reply.sfGood )
  265.         {
  266.         SoundConvertInfo convertInfo;
  267.         SoundConverter sc;
  268.         OSErr err;
  269.     
  270.         convertInfo.file = reply.sfFile;
  271.         GetWantedData( dialog, &convertInfo.info );
  272.                 
  273.         err = SoundConverterOpen( &FileInfo.info, &convertInfo.info, &sc );
  274.         if ( err )
  275.             ShowErr( "SoundConverterOpen failed", err );
  276.         else
  277.             {
  278.             if ( BuffersSize == 0 )
  279.                 {
  280.                 BuffersSize = MaxBlock();
  281.                 BuffersSize = BuffersSize * 0.4;    // try 40% of available space
  282.                 }
  283.             
  284.             err = SoundConverterGetBufferSizes( sc, BuffersSize,
  285.                             &convertInfo.inputBufferFrames,
  286.                             &convertInfo.inputBufferBytes,
  287.                             &convertInfo.outputBytes );
  288.             if ( err )
  289.                 ShowErr( "SoundConverterGetBufferSizes failed", err );
  290.             else
  291.                 ConvertSound( &FileInfo, &convertInfo, sc );
  292.  
  293.             SoundConverterClose(sc);
  294.             }
  295.         }
  296.     }
  297.  
  298. // Actually convert sound from input to output
  299.  
  300. OSErr ConvertSound( SoundFileInfo*input, SoundConvertInfo*output, SoundConverter sc )
  301.     {
  302.     OSErr err=0;
  303.     short inputFile=0, outputFile=0;
  304.     
  305.     // make buffers
  306.  
  307.     input->buffer = output->buffer = 0;
  308.     
  309.     input->buffer = NewPtr( output->inputBufferBytes );
  310.     err = MemError();
  311.     if ( err )
  312.         {
  313.         ShowErr( "creating input buffer", err );
  314.         goto CLEANUP;
  315.         }
  316.     output->buffer = NewPtr( output->outputBytes );
  317.     err = MemError();
  318.     if ( err )
  319.         {
  320.         ShowErr( "creating output buffer", err );
  321.         goto CLEANUP;
  322.         }
  323.     
  324.     // open files
  325.     
  326.     err = FSpOpenDF( &input->file, fsCurPerm, &inputFile );
  327.     if ( err )
  328.         {
  329.         ShowErr( "opening input file", err );
  330.         goto CLEANUP;
  331.         }
  332.         
  333.     FSpCreate ( &output->file, 'SCPL', 'AIFC', 0);    // a SoundApp creator & filetype
  334.     err = FSpOpenDF( &output->file, fsRdWrPerm, &outputFile );
  335.     if ( err )
  336.         {
  337.         ShowErr( "opening output file", err );
  338.         goto CLEANUP;
  339.         }
  340.     SetEOF( outputFile, 0 );
  341.  
  342.     SoundConverterBeginConversion( sc );
  343.     
  344.     // if it fits in memory, do it in one shot
  345.  
  346.     if ( input->numFrames <= output->inputBufferFrames )
  347.         {
  348.         err = ConvertBufferInMemory( input, inputFile, output, outputFile, sc );
  349.         if ( err )
  350.             goto CLEANUP;
  351.         }
  352.  
  353.     // otherwise convert it in chunks
  354.  
  355.     else
  356.         {
  357.         err = ConvertBufferInChunks( input, inputFile, output, outputFile, sc );
  358.         if ( err )
  359.             goto CLEANUP;
  360.         }
  361.     
  362. CLEANUP:
  363.  
  364.     if ( input->buffer )
  365.         DisposePtr( input->buffer );
  366.     if ( output->buffer )
  367.         DisposePtr( output->buffer );
  368.     if ( inputFile )
  369.         FSClose( inputFile );
  370.     if ( outputFile )
  371.         FSClose( outputFile );
  372.     FlushVol( "\p", output->file.vRefNum );
  373.     
  374.     return err;
  375.     }
  376.  
  377. // convert the input buffer when it fits in memory
  378.  
  379. OSErr ConvertBufferInMemory( SoundFileInfo*input, short inputFile,
  380.                     SoundConvertInfo*output, short outputFile, SoundConverter sc )
  381.     {
  382.     unsigned long actualOutputFrames=0;
  383.     unsigned long actualOutputSize=0;
  384.     unsigned long additionalOutputFrames=0;
  385.     unsigned long additionalOutputSize=0;
  386.     long inputFileSize;
  387.     OSErr err;
  388.  
  389.     GetEOF( inputFile, &inputFileSize );
  390.  
  391.     err = SetFPos( inputFile, fsFromStart, input->dataOffset );
  392.     if ( err )
  393.         return ShowErr( "setting position in input file", err );
  394.     inputFileSize -= input->dataOffset;
  395.  
  396.     err = FSRead( inputFile, &inputFileSize, input->buffer );
  397.     if ( err )
  398.         return ShowErr( "reading input file", err );
  399.  
  400.     err = SoundConverterConvertBuffer( sc,
  401.                         input->buffer,
  402.                         input->numFrames,
  403.                         output->buffer,
  404.                         &actualOutputFrames,
  405.                         &actualOutputSize );
  406.     if ( err )
  407.         return ShowErr( "converting sound", err );
  408.     
  409.     err = SetupAIFFHeader( outputFile,
  410.                         output->info.numChannels,
  411.                         output->info.sampleRate,
  412.                         output->info.sampleSize,
  413.                         output->info.format,
  414.                         actualOutputSize,
  415.                         actualOutputFrames );
  416.     if ( err )
  417.         return ShowErr( "setting AIFF header in file", err );
  418.     
  419.     err = FSWrite( outputFile, (long*)&actualOutputSize, output->buffer );
  420.     if ( err )
  421.         return ShowErr( "writing to output file", err );
  422.     
  423.     // end the conversion, and see if you get back a few more bytes of data
  424.     
  425.     err = SoundConverterEndConversion( sc, output->buffer,
  426.             &additionalOutputFrames, &additionalOutputSize );
  427.     if ( err )
  428.         return ShowErr( "ending conversion", err );
  429.     
  430.     // if we got a dribble more, write it to disk, then update header
  431.     
  432.     if ( additionalOutputFrames )
  433.         {
  434.         SysBeep(1);
  435.         err = FSWrite( outputFile, (long*)&additionalOutputSize, output->buffer );
  436.         if ( err )
  437.             return ShowErr( "2nd writing to output file", err );
  438.         
  439.         err = SetFPos(outputFile, fsFromStart, 0);
  440.         if ( err )
  441.             return ShowErr( "setting file position to 0", err );
  442.         
  443.         err = SetupAIFFHeader( outputFile,
  444.                             output->info.numChannels,
  445.                             output->info.sampleRate,
  446.                             output->info.sampleSize,
  447.                             output->info.format,
  448.                             actualOutputSize+additionalOutputSize,
  449.                             actualOutputFrames+additionalOutputFrames );
  450.         if ( err )
  451.             return ShowErr( "2nd setting AIFF header in file", err );
  452.         }
  453.  
  454.     return 0;
  455.     }
  456.  
  457. // convert a sound file that's too big to convert in memory at once
  458.  
  459. OSErr ConvertBufferInChunks( SoundFileInfo*input, short inputFile,
  460.                     SoundConvertInfo*output, short outputFile, SoundConverter sc )
  461.     {
  462.     OSErr err;
  463.     long inputFileSize;
  464.     long currentFrames, framesLeft=input->numFrames;
  465.     long bytesRead;
  466.     long byteWritten=0, framesWritten=0;
  467.     unsigned long actualOutputFrames=0;
  468.     unsigned long actualOutputSize=0;
  469.     unsigned long additionalOutputFrames=0;
  470.     unsigned long additionalOutputSize=0;
  471.     
  472.     // setup input file for reading
  473.  
  474.     GetEOF( inputFile, &inputFileSize );
  475.     err = SetFPos( inputFile, fsFromStart, input->dataOffset );
  476.     if ( err )
  477.         return ShowErr( "setting position in input file", err );
  478.     inputFileSize -= input->dataOffset;
  479.     
  480.     // setup dummy header ( we'll update when done )
  481.  
  482.     err = SetupAIFFHeader( outputFile,
  483.                     output->info.numChannels,
  484.                     output->info.sampleRate,
  485.                     output->info.sampleSize,
  486.                     output->info.format,
  487.                     0,
  488.                     0 );
  489.     if ( err )
  490.         return ShowErr( "setting AIFF header in file", err );
  491.  
  492.     currentFrames = output->inputBufferFrames;
  493.     
  494.     // loop through buffers of size = output->inputBufferFrames
  495.  
  496.     while ( framesLeft > 0 )
  497.         {
  498.         // read a buffer full from input file
  499.         
  500.         bytesRead = output->inputBufferBytes;
  501.         err = FSRead( inputFile, &bytesRead, input->buffer );
  502.         if ( err != 0 && err != -39 )
  503.             return ShowErr( "reading input file", err );
  504.         
  505.         // convert the buffer
  506.         
  507.         err = SoundConverterConvertBuffer( sc,
  508.                     input->buffer,
  509.                     currentFrames,
  510.                     output->buffer,
  511.                     &actualOutputFrames,
  512.                     &actualOutputSize );
  513.         if ( err )
  514.             return ShowErr( "converting sound buffer", err );
  515.         
  516.         // write the result to output file
  517.         
  518.         err = FSWrite( outputFile, (long*)&actualOutputSize, output->buffer );
  519.         if ( err )
  520.             return ShowErr( "writing sound buffer to file", err );
  521.  
  522.         byteWritten += actualOutputSize;
  523.         framesWritten += actualOutputFrames;
  524.         
  525.         // calculate remaining frames and adjust currentFrames for last buffer
  526.         
  527.         framesLeft -= currentFrames;
  528.         if ( framesLeft < output->inputBufferFrames )
  529.             currentFrames = framesLeft;
  530.         } 
  531.  
  532.     // end the conversion, and see if you get back a few more bytes of data
  533.     
  534.     err = SoundConverterEndConversion( sc, output->buffer,
  535.             &additionalOutputFrames, &additionalOutputSize );
  536.     if ( err )
  537.         return ShowErr( "ending conversion", err );
  538.     
  539.     // if we got a dribble more, write it to disk, then update header
  540.     
  541.     if ( additionalOutputFrames )
  542.         {
  543.         err = FSWrite( outputFile, (long*)&additionalOutputSize, output->buffer );
  544.         if ( err )
  545.             return ShowErr( "2nd writing to output file", err );
  546.         }
  547.         
  548.     err = SetFPos(outputFile, fsFromStart, 0);
  549.     if ( err )
  550.         return ShowErr( "setting file position to 0", err );
  551.     
  552.     err = SetupAIFFHeader( outputFile,
  553.                         output->info.numChannels,
  554.                         output->info.sampleRate,
  555.                         output->info.sampleSize,
  556.                         output->info.format,
  557.                         byteWritten+additionalOutputSize,
  558.                         framesWritten+additionalOutputFrames );
  559.     if ( err )
  560.         return ShowErr( "2nd setting AIFF header in file", err );
  561.     
  562.     return 0;
  563.     }
  564.  
  565. // Get and show info of current input file
  566.  
  567. void ShowInfo( DialogPtr dialog )
  568.     {
  569.     SetStaticText( dialog, Static_Filename, FileInfo.file.name );
  570.     SetStaticText( dialog, Static_Notes, "\p" );
  571.  
  572.     if ( FileInfo.file.name[0] != 0 )
  573.         {
  574.         short fileRef;
  575.         Str255 s;
  576.     
  577.         OSErr err = FSpOpenDF( &FileInfo.file, fsCurPerm, &fileRef );
  578.         if ( err )
  579.             {
  580.             ShowErr( "opening input file", err );
  581.             goto PUNT;
  582.             }
  583.     
  584.         err = ParseAIFFHeader( fileRef, &FileInfo.info, &FileInfo.numFrames, &FileInfo.dataOffset );
  585.         
  586.         FSClose( fileRef );
  587.  
  588.         if ( err )
  589.             {
  590.             ShowErr( "reading AIFF header", err );
  591.             goto PUNT;
  592.             }
  593.     
  594.         MakeInfoString( &FileInfo, s );
  595.         SetStaticText( dialog, Static_Notes, s );
  596.         return;
  597.         }
  598. PUNT:
  599.     SetStaticText( dialog, Static_Notes, "\p" );
  600.     }
  601.  
  602. // Set a SoundComponentData with current dialog settings
  603.  
  604. void GetWantedData(DialogPtr dialog, SoundComponentData* info)
  605.     {
  606.     short formatPopupIndex = GetAControlValue( dialog, Popup_Format );
  607.     short ratePopupIndex = GetAControlValue( dialog, Popup_Rate );
  608.     short isMono = GetRadio( dialog, Radio_Mono );
  609.     short is8Bit = GetRadio( dialog, Radio_8bit );
  610.     
  611.     info->flags = 0;
  612.     info->format = (*MenuToFormatTypeList)[ formatPopupIndex-1 ].formatType;
  613.     info->numChannels = isMono ? 1 : 2;
  614.     info->sampleSize = is8Bit ? 8 : 16;
  615.     info->sampleRate = MenuToSampleRates[ ratePopupIndex-1 ];
  616.     info->sampleCount = 0;
  617.     info->buffer = 0;
  618.     info->reserved = 0;
  619.     }
  620.  
  621. // build a string describing the current file
  622.  
  623. void MakeInfoString( SoundFileInfo* fileInfo, Byte* s )
  624.     {
  625.     char stereoString[16], sampleSizeString[8], sampleRateString[16], formatString[64];
  626.     double_t samplesPerSec;
  627.     short i, n;
  628.     Fixed f = fileInfo->info.sampleRate & 0x80000000L;
  629.     
  630.     if ( fileInfo->info.numChannels >= 2 )
  631.         strcpy( stereoString, "stereo" );
  632.     else
  633.         strcpy( stereoString, "mono" );
  634.     
  635.     sprintf( sampleSizeString, "%hd bit", fileInfo->info.sampleSize );
  636.     
  637.     samplesPerSec = Fix2X( fileInfo->info.sampleRate & 0x7fffffffL );    // unsigned Fixed value
  638.     if ( f )
  639.         samplesPerSec += 32768.0;
  640.     sprintf( sampleRateString, "%.3lf", samplesPerSec/1000.0 );
  641.     
  642.     n = GetHandleSize( (Handle) MenuToFormatTypeList ) / sizeof( MenuToFormatType );
  643.     for ( i=0; i<n; i++ )
  644.         if ( (*MenuToFormatTypeList)[i].formatType == fileInfo->info.format )
  645.             {
  646.             GetMenuItemText( GetMHandle( FormatPopupMenu ), i+1, (Byte*)formatString );
  647.             p2cstr( (Byte*)formatString );
  648.             break;
  649.             }
  650.     if ( i == n )
  651.         strcpy( formatString, "unknown" );
  652.     
  653.     sprintf( (char*)s, "File has %s %s sound, recorded at %s khz, with a format of “%s.”",
  654.             sampleSizeString, stereoString, sampleRateString, formatString );
  655.     c2pstr( (char*)s );
  656.     }
  657.  
  658. // Find all compressor components and add them to the format popup
  659.  
  660. void BuildFormatMenu(void)
  661.     {
  662.     Component component=0;
  663.     ComponentDescription desc, info;
  664.     Handle name = NewHandle(0);
  665.     MenuHandle menu = GetMHandle( FormatPopupMenu );    
  666.     short compCount=3, i;
  667.  
  668.     MenuToFormatTypeList = (MenuToFormatType**)NewHandleClear(3*sizeof(MenuToFormatType));
  669.     
  670.     // add the built in types
  671.  
  672.     (*MenuToFormatTypeList)[0].formatType = kOffsetBinary;
  673.     (*MenuToFormatTypeList)[0].isCompressor = 
  674.         (*MenuToFormatTypeList)[0].isDecompressor = true;
  675.  
  676.     (*MenuToFormatTypeList)[1].formatType = kTwosComplement;
  677.     (*MenuToFormatTypeList)[1].isCompressor = 
  678.         (*MenuToFormatTypeList)[1].isDecompressor = true;
  679.  
  680.     (*MenuToFormatTypeList)[2].formatType = 0;
  681.     
  682.     // scan through the compressors
  683.  
  684.     desc.componentType = kSoundCompressor;
  685.     desc.componentSubType = 0;
  686.     desc.componentManufacturer = 0;
  687.     desc.componentFlags = 0;
  688.     desc.componentFlagsMask = 0;
  689.     
  690.     while ( ( component = FindNextComponent( component, &desc ) ) != 0 )
  691.         {
  692.         GetComponentInfo( component, &info, name, 0, 0 );
  693.         if ( GetHandleSize(name) )
  694.             {
  695.             MenuToFormatType data;
  696.             
  697.             data.formatType = info.componentSubType;
  698.             data.isCompressor = true;
  699.             
  700.             AppendMenu( menu, "\p " );
  701.             HLock( name );
  702.             SetMenuItemText( menu, CountMItems(menu), (Byte*)*name );
  703.             HUnlock( name );
  704.             PtrAndHand( (Ptr)&data, (Handle)MenuToFormatTypeList, sizeof(MenuToFormatType) );
  705.             compCount++;
  706.             }
  707.         }
  708.     
  709.     // scan through the decompressors
  710.     
  711.     desc.componentType = kSoundDecompressor;
  712.     desc.componentSubType = 0;
  713.     desc.componentManufacturer = 0;
  714.     desc.componentFlags = 0;
  715.     desc.componentFlagsMask = 0;
  716.     
  717.     while ( ( component = FindNextComponent( component, &desc ) ) != 0 )
  718.         {
  719.         GetComponentInfo( component, &info, name, 0, 0 );
  720.         if ( GetHandleSize(name) && info.componentSubType )
  721.             {
  722.             // see if we have a compressor already, and if so, mark it
  723.  
  724.             MenuToFormatTypePtr p = *MenuToFormatTypeList;
  725.             for ( i=0; i<compCount; i++, p++ )
  726.                 if ( info.componentSubType == p->formatType )
  727.                     {
  728.                     p->isDecompressor = true;
  729.                     break;
  730.                     }
  731.             
  732.             // else create a new entry    
  733.             
  734.             if ( i == compCount )
  735.                 {
  736.                 MenuToFormatType data;
  737.                 
  738.                 data.formatType = info.componentSubType;
  739.                 data.isDecompressor = true;
  740.                 
  741.                 AppendMenu( menu, "\p " );
  742.                 HLock( name );
  743.                 SetMenuItemText( menu, CountMItems(menu), (Byte*)*name );
  744.                 HUnlock( name );
  745.                 PtrAndHand( (Ptr)&data, (Handle)MenuToFormatTypeList, sizeof(MenuToFormatType) );
  746.                 }
  747.             }
  748.         }
  749.     
  750.     DisposeHandle( name );
  751.     }
  752.  
  753. // --------- just some utility routines ---------------------------------------------------
  754.  
  755. // handle a few items in the dialog
  756.  
  757. pascal Boolean MyFilter( DialogPtr dialog, EventRecord *evt, short *itemHit )
  758.     {
  759.     WindowPtr w = (WindowPtr)(evt->message);
  760.     Boolean ans = false;
  761.  
  762.     switch(evt->what)
  763.         {
  764.         case updateEvt:
  765.             if ( w == dialog )
  766.                 {
  767.                 DoDialogUpdate(dialog);
  768.                 ans = true;
  769.                 *itemHit = 0;
  770.                 }
  771.             break;
  772.         
  773.         case mouseDown:
  774.         case mouseUp:
  775.             Where = evt->where;
  776.             GlobalToLocal(&Where);
  777.             Modifiers = evt->modifiers;
  778.             break;
  779.         }
  780.  
  781.     return ans ;
  782.     }
  783.  
  784. void DoDialogUpdate( DialogPtr dialog)
  785.     {
  786.     GrafPtr oldPort;
  787.  
  788.     GetPort(&oldPort);
  789.     SetPort(dialog);
  790.     BeginUpdate(dialog);
  791.  
  792.     UpdtDialog(dialog,dialog->visRgn);
  793.  
  794.     EndUpdate(dialog);
  795.     SetPort(oldPort);
  796.     }
  797.  
  798. void SetStaticText( DialogPtr dlog, short item, Byte* s )
  799.     {
  800.     short type;
  801.     Handle hndl;
  802.     Rect box;
  803.  
  804.     GetDialogItem(dlog,item,&type,&hndl,&box);
  805.     SetDialogItemText( hndl, s );
  806.     }
  807.  
  808. void ShowAControl( DialogPtr dlog, short item )
  809.     {
  810.     short type;
  811.     Handle hndl;
  812.     Rect box;
  813.  
  814.     GetDialogItem(dlog,item,&type,&hndl,&box);
  815.     ShowControl( (ControlHandle)hndl );
  816.     }
  817.  
  818. void HiliteAControl( DialogPtr dlog, short item, Boolean state )
  819.     {
  820.     short type;
  821.     Handle hndl;
  822.     Rect box;
  823.  
  824.     GetDialogItem(dlog,item,&type,&hndl,&box);
  825.     HiliteControl( (ControlHandle)hndl, state? 0 : 255 );
  826.     }
  827.  
  828. void SetRadio(DialogPtr dlog, short item, short val)
  829.     {
  830.     short type;
  831.     Handle hndl;
  832.     Rect box;
  833.  
  834.     GetDialogItem(dlog,item,&type,&hndl,&box);
  835.     SetControlValue((ControlHandle)hndl,val!=0);
  836.     }
  837.  
  838. short GetRadio(DialogPtr dlog, short item)
  839.     {
  840.     short type;
  841.     Handle hndl;
  842.     Rect box;
  843.     
  844.     GetDialogItem(dlog,item,&type,&hndl,&box);
  845.     return GetControlValue((ControlHandle)hndl) != 0;
  846.     }
  847.  
  848. short GetAControlValue(DialogPtr dlog, short item)
  849.     {
  850.     short type;
  851.     Handle hndl;
  852.     Rect box;
  853.     
  854.     GetDialogItem(dlog,item,&type,&hndl,&box);
  855.     return GetControlValue((ControlHandle)hndl);
  856.     }
  857.  
  858. OSErr ShowErr(char*text, short err)
  859.     {
  860.     char s[256];
  861.     if (err)
  862.         sprintf((char*)s, "Failure at %s, with error = %hd.", text, err);
  863.     else
  864.         sprintf((char*)s, "%s.", text);
  865.     c2pstr(s);
  866.     ParamText((Byte*)s, 0, 0, 0);
  867.     NoteAlert(128, 0);
  868.     return err;
  869.     }
  870.  
  871. void ShowErrAndQuit(char*text, short err)
  872.     {
  873.     ShowErr( text, err );
  874.     ExitToShell();
  875.     }
  876.